import * as md from "./md";

class EventBus {
  private readonly hs: gt.other.EventBusHandle[] = [{
    type: /msgRecv/,
    callBack(data) {
      md.format.msg(data).then(d => {
        md.gd.msg.push(d);
      });
    },
  }];
  constructor () { }
  create(type: string | RegExp, callBack: (data: any) => any) {
    if (type && callBack instanceof Function) {
      this.hs.push({ type: new RegExp(type), callBack });
    }
  }
  arrival(type: string, data?: any) {
    for (const e of this.hs) {
      if (e.type.test(type)) {
        try { e.callBack(data); } catch (_) { this.remove(e.callBack); }
      }
    }
  }
  remove(callback: cbk) {
    let i = this.hs.length;
    while (i--) {
      if (this.hs[i].callBack == callback) {
        this.hs.splice(i, 1);
      }
    }
  }
}
const me = md.format.def.user as gt.sql.user;
export const
  geb = new EventBus(), createEvent = geb.create.bind(geb), arrivalEvent = geb.arrival.bind(geb), removeEvent = geb.remove.bind(geb),
  api = {
    me, mid: "",
    login(data: { username: string, password: string; timeout?: number; }) {
      return new Promise<gt.sql.user>(async (resolve) => {
        const res = await request({ data, url: "/login" });
        if (typeof res.data.data === "string") {
          localStorage.setItem("token", res.data.data);
        }
        resolve(res.data.data);
      });
    },
    reg(data: { username: string; password: string; name: string; }) {
      return new Promise<string>(async (resolve) => {
        const res = await request({ data, url: "/reg" });
        if (typeof res.data.data.token === "string") {
          localStorage.setItem("token", res.data.data.token);
        }
        resolve(res.data.data);
      });
    },
    get token() {
      return (uni.getStorageSync("token") || "") as string;
    },
    set token(p: String) {
      if (p && typeof p === "string") {
        uni.setStorageSync("token", p);
      }
    },
    async request(data?: any, type?: string) {
      while (!this.token) {
        // #ifdef MP-WEIXIN
        if (await wxlogin()) {
          break;
        }
        // #endif
        msg({ title: "登录失败", icon: "error" });
        throw "需要登陆";
      }
      if (!this.mid) {
        await setMe(await request({}, "user/me"));
      }
      if (!type) {
        try {
          type = "";
          throw new Error();
        } catch (e: any) {
          type = e.stack.split("\n")[2].replace(/\(.*\)/g, "").replace(/\sat\s/g, "").replace(/\s+/g, "") as string;
          type = type.substring(type.lastIndexOf(".") + 1);
        }
      }
      if (md.type(data) == "object" && typeof data.id != "undefined") {
        if (type.indexOf("Read") > 0 && (!data.id || !data.id.length)) {
          if (data["#page"]) {
            return Object.assign({ current: 1, size: 10, total: 0 }, data["#page"], { data: [] });
          }
          return [];
        }
      }
      return request(data, type);
    },
    logout() {
      uni.clearStorage();
    }, wxlogin
  };
export async function setMe(me: gt.sql.user) {
  api.me = await format.user(me);
  api.mid = api.me.id;
  api.token = api.me.token;
}
export function wxlogin() {
  return new Promise<gt.sql.user | void>(async (resolve) => {
    uni.request({
      method: "POST", url: md.formatUrl("/wxlogin", md.apiUrl), data: await uni.login({ provider: "weixin", onlyAuthorize: true, }),
      async success(res) {
        const d: any = res.data;
        if (d.message) {
          const icon = d.type || (d.data ? "success" : "error");
          msg({ icon, title: d.message });
          if (!d.data) {
            return resolve();
          }
        }
        if (d.data.id) {
          await setMe(d.data);
          resolve(api.me);
        } else {
          msg({ title: "登录失败", icon: "error" });
          resolve();
        }
      },
      fail(r) { msg({ icon: "error", title: r.errMsg }); resolve(); }
    });
  });
}
export function msg(opt: UniApp.ShowToastOptions) {
  if (opt.mask === undefined) {
    opt.mask = true;
  }
  return uni.showToast(opt);
}

export function request(data?: obj, url?: string) {
  return new Promise<any>(async (resolve, reject) => {
    await next();
    if (!url) {
      url = md.apiUrl;
    }
    url = md.formatUrl(url, md.apiUrl);
    const md5 = md.md5(JSON.stringify({ url, data }));
    if (md.addCache(md5, resolve, reject)) {
      uni.request({
        url, data, method: "POST",
        header: { token: uni.getStorageSync("token") },
        async success(res) {
          const d: any = res.data;
          if (d?.message) {
            if (d.message.indexOf("登录") >= 0) {
              uni.removeStorageSync("token");
              // #ifdef MP-WEIXIN
              await wxlogin();
              return await request(data, url);
              // #endif
              return reject("未登录");
            }
            const icon = d.type || (d.data ? "success" : "error");
            msg({ icon, title: d.message });
            if (!d.data) {
              return reject(d);
            }
          }
          // resolve(d);
          md.execCache(md5, d);
        },
        fail(r) {
          msg({
            icon: "error",
            title: r.errMsg
          });
          // reject(r);
          md.execCache(md5, undefined, 1);
        }
      });
    }
  });
}
export function upload(opt: Omit<UniApp.UploadFileOption, "url">) {
  return uni.uploadFile(Object.assign(opt, { url: md.apiUrl + "upload" }));
}
export function onLoaded(callback: cbk) {
  uni.$on("loaded", callback);
  callback();
}
const exg = { createEvent, arrivalEvent, removeEvent, request, api, msg, upload, next: md.next };
for (const key in exg) {
  // @ts-ignore
  globalThis[key] = exg[key];
  // #ifdef MP-WEIXIN
  // @ts-ignore
  global[key] = exg[key];
  // #endif
}
